package org.dromara.common.core.config

import io.github.oshai.kotlinlogging.KotlinLogging
import jakarta.annotation.PreDestroy
import org.apache.commons.lang3.concurrent.BasicThreadFactory
import org.dromara.common.core.config.properties.ThreadPoolProperties
import org.dromara.common.core.utils.SpringUtils.isVirtual
import org.dromara.common.core.utils.Threads.printException
import org.dromara.common.core.utils.Threads.shutdownAndAwaitTermination
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.core.task.VirtualThreadTaskExecutor
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.ThreadPoolExecutor

/**
 * 线程池配置
 *
 * @author Lion Li
 * @author LikeYouDo
 */
@AutoConfiguration
@EnableConfigurationProperties(ThreadPoolProperties::class)
class ThreadPoolConfig {

    companion object {
        private val log = KotlinLogging.logger {}
    }

    /**
     * 核心线程数 = cpu 核心数 + 1
     */
    private val core = Runtime.getRuntime().availableProcessors() + 1

    private lateinit var scheduledExecutorService: ScheduledExecutorService

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = ["scheduledExecutorService"])
    protected fun scheduledExecutorService(): ScheduledExecutorService {
        // daemon 必须为 true
        val builder = BasicThreadFactory.Builder().daemon(true)
        if (isVirtual()) {
            builder.namingPattern("virtual-schedule-pool-%d")
                .wrappedFactory(VirtualThreadTaskExecutor().virtualThreadFactory)
        } else {
            builder.namingPattern("schedule-pool-%d")
        }
        // 匿名内部类，线程名称格式为：schedule-pool-%d
        val scheduledThreadPoolExecutor = object : ScheduledThreadPoolExecutor(
            core,
            builder.build(),
            CallerRunsPolicy()
        ) {
            override fun afterExecute(r: Runnable, t: Throwable?) {
                super.afterExecute(r, t)
                printException(r, t)
            }
        }
        this.scheduledExecutorService = scheduledThreadPoolExecutor
        return scheduledThreadPoolExecutor
    }

    /**
     * 销毁事件
     */
    @PreDestroy
    fun destroy() {
        try {
            log.info { "====关闭后台任务任务线程池====" }
            shutdownAndAwaitTermination(scheduledExecutorService)
        } catch (e: Exception) {
            log.error(e) { e.message }
        }
    }

}
